package bsh.asm.acessor;

import org.objectweb.asm.MethodVisitor;

import bsh.CompilationState;
import bsh.CompiledScript;
import bsh.ReflectionUtils;
import bsh.meta.JavaClassWrapper;
import bsh.meta.MethodDescriptor;
import bsh.meta.TypeWrapper;

/**
 * {@link ObjectAccessor} para os campos dinamicos.
 * 
 * @author takeshi
 */
public class DynamicFieldAccessor implements ObjectAccessor {

    private final ThisObjectAccessor accessor;

    private final MethodDescriptor getter;

    private final MethodDescriptor setter;

    private final String name;

    /**
     * @param accessor {@link ThisObjectAccessor}
     * @param reflection {@link ReflectionUtils}
     * @param name String
     */
    public DynamicFieldAccessor(ThisObjectAccessor accessor, ReflectionUtils reflection, String name) {
        super();
        this.accessor = accessor;
        this.name = name;
        this.getter = reflection.getMethodWithName(CompiledScript.class, "getFieldValue");
        this.setter = reflection.getMethodWithName(CompiledScript.class, "setField");
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#loadObject(org.objectweb.asm.MethodVisitor, bsh.CompilationState)
     */
    public void loadObject(MethodVisitor visitor, CompilationState state) {
        this.accessor.loadObject(visitor, state);
        visitor.visitLdcInsn(this.name);
        state.pushStack(String.class);
        this.getter.writeInvoke(visitor, state);
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#preStore(org.objectweb.asm.MethodVisitor, bsh.CompilationState)
     */
    public void preStore(MethodVisitor visitor, CompilationState state) {
        this.accessor.loadObject(visitor, state);
        visitor.visitLdcInsn(this.name);
        state.pushStack(String.class);
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#readOnly()
     */
    public boolean readOnly() {
        return false;
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#storeObject(org.objectweb.asm.MethodVisitor, bsh.CompilationState)
     */
    public void storeObject(MethodVisitor visitor, CompilationState state) {
        this.setter.writeInvoke(visitor, state);
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#type()
     */
    public TypeWrapper type() {
        return JavaClassWrapper.OBJECT_WRAPPER;
    }

}
